package com.card.framework.mybatis.plugin;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;

import org.apache.ibatis.executor.parameter.DefaultParameterHandler;
import org.apache.ibatis.executor.statement.BaseStatementHandler;
import org.apache.ibatis.executor.statement.RoutingStatementHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.log4j.Logger;

import com.card.framework.mybatis.plugin.dialect.DefaultDialect;
import com.card.framework.mybatis.plugin.dialect.MySQLDialect;
import com.card.framework.page.model.PageModel;
import com.card.framework.util.ReflectHelper;

/**
 * 
 * @author wwz
 * @see
 */
@Intercepts( { @Signature(type = StatementHandler.class, method = "prepare", args = { Connection.class }) })
public class MyFrameworkDialectPlugin implements Interceptor {
	
	static int CONNECTION_INDEX = 0;
	DefaultDialect dialect = new MySQLDialect();
	Logger loger = Logger.getLogger(MyFrameworkDialectPlugin.class);
	/**
	 * 
	 * @param queryArgs
	 * @throws SQLException 
	 */
	public Object intercept(Invocation ivk) throws Throwable {
		if (ivk.getTarget() instanceof RoutingStatementHandler) {
			RoutingStatementHandler statementHandler = (RoutingStatementHandler) ivk.getTarget();
			BaseStatementHandler delegate = (BaseStatementHandler) ReflectHelper.getValueByFieldName(statementHandler, "delegate");
			MappedStatement mappedStatement = (MappedStatement) ReflectHelper.getValueByFieldName(delegate, "mappedStatement");
			BoundSql boundSql = delegate.getBoundSql();
			Object parameterObject = boundSql.getParameterObject();// 分页SQL<select>中parameterType属性对应的实体参数，即Mapper接口中执行分页方法的参数,该参数不得为空
			if (parameterObject == null) {
				throw new NullPointerException("parameterObject尚未实例化！");
			} else {
				PageModel page = null;
				if (parameterObject instanceof PageModel) { // 参数就是PageModel实体
					page = (PageModel) parameterObject;
				} else { // 参数为某个实体，该实体拥有PageModel属性
					Field pageField = ReflectHelper.getFieldByFieldName(parameterObject, "page");
					if (pageField != null) {
						page = (PageModel) ReflectHelper.getValueByFieldName(parameterObject, "page");
						if (page == null) {
							return ivk.proceed();
						}
					} else {
						// 不存在page属性
						return ivk.proceed();
					}
				}
				Connection connection = (Connection) ivk.getArgs()[0];
				String sql = boundSql.getSql();
				String countSql = "select count(0) from (" + sql + ") tmp_count"; // 记录统计
				loger.info(countSql);
				PreparedStatement countStmt = connection.prepareStatement(countSql);
				ReflectHelper.setValueByFieldName(boundSql, "sql", countSql); 
				
				DefaultParameterHandler ParameterHandler = new DefaultParameterHandler(mappedStatement, parameterObject, boundSql);
				ParameterHandler.setParameters(countStmt);
				ResultSet rs = countStmt.executeQuery();
				int count = 0;
				if (rs.next()) {
					count = rs.getInt(1);
				}
				rs.close();
				countStmt.close();
				page.setTotalCount(count);
				String pageSql = dialect.getLimitString(sql, page.getPage(), page.getRows());
				loger.info(pageSql);
				ReflectHelper.setValueByFieldName(boundSql, "sql", pageSql); // 将分页sql语句反射回BoundSql.

			}
		}
		return ivk.proceed();
	}

	public Object plugin(Object target) {
		return Plugin.wrap(target, this);
	}

	public void setProperties(Properties properties) {
	}
}